import HexUtils from '@/utils/HexUtils'
import Base64Utils from '@/utils/Base64Utils'

export default class RSA {
  private publicKey: CryptoKey | null = null
  private privateKey: CryptoKey | null = null
  private initialized: boolean = false

  private publicKeyBase64?: string
  private privateKeyBase64?: string

  /**
   * 私有构造函数，防止外部直接实例化
   * @param publicKeyBase64 - Base64 格式的公钥
   * @param privateKeyBase64 - Base64 格式的私钥
   */
  private constructor(publicKeyBase64?: string, privateKeyBase64?: string) {
    this.publicKeyBase64 = publicKeyBase64
    this.privateKeyBase64 = privateKeyBase64
  }

  /**
   * 静态方法，用于创建并初始化 RSA 实例，如果不传任何参数，则随机生成公钥和私钥，如果只传入公钥，只支持加密操作，如果同时传入，只支持公钥加密，私钥解密
   * @param publicKeyBase64 - Base64 格式的公钥
   * @param privateKeyBase64 - Base64 格式的私钥
   * @returns 初始化后的 RSA 实例
   */
  public static async initRSA(publicKeyBase64?: string, privateKeyBase64?: string): Promise<RSA> {
    const rsa = new RSA(publicKeyBase64, privateKeyBase64)
    await rsa.initialize()
    return rsa
  }

  /**
   * 异步初始化公钥和私钥
   */
  private async initialize(): Promise<void> {
    if (this.initialized) return
    try {

      if (!this.publicKeyBase64) {
        if (this.privateKeyBase64) {
          return Promise.reject('不允许只设置私钥')
        }
        await this.generateKeyPair()
      } else {
        await this._importPublicKey(this.publicKeyBase64)
        if (this.privateKeyBase64) {
          await this._importPrivateKey(this.privateKeyBase64)
        }
      }
      this.initialized = true
    } catch (error) {
      console.error('初始化密钥对失败:', error)
      throw error
    }
  }

  /**
   * 从 Base64 格式的字符串导入公钥
   * @param base64Key - Base64 格式的公钥
   */
  private async _importPublicKey(base64Key: string): Promise<void> {
    const keyBuffer = Base64Utils.base64ToBuffer(base64Key)
    try {
      this.publicKey = await crypto.subtle.importKey(
        'spki',
        keyBuffer,
        {
          name: 'RSA-OAEP',
          hash: 'SHA-256'
        },
        false,
        ['encrypt']
      )
    } catch (error) {
      console.error('导入公钥失败:', error)
      throw error
    }
  }

  /**
   * 从 Base64 格式的字符串导入私钥
   * @param base64Key - Base64 格式的私钥
   */
  private async _importPrivateKey(base64Key: string): Promise<void> {
    const keyBuffer = Base64Utils.base64ToBuffer(base64Key)
    try {
      this.privateKey = await crypto.subtle.importKey(
        'pkcs8',
        keyBuffer,
        {
          name: 'RSA-OAEP',
          hash: 'SHA-256'
        },
        false,
        ['decrypt']
      )
    } catch (error) {
      console.error('导入私钥失败:', error)
      throw error
    }
  }

  /**
   * 生成公钥和私钥对
   */
  private async generateKeyPair(): Promise<void> {
    try {
      const keyPair = await crypto.subtle.generateKey(
        {
          name: 'RSA-OAEP',
          modulusLength: 2048, // 可以选择 1024, 2048, 4096 等
          publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 常见的公钥指数
          hash: 'SHA-256' // 可以选择 SHA-1, SHA-256, SHA-384, SHA-512 等
        },
        true, // 是否可导出密钥
        ['encrypt', 'decrypt'] // 密钥用途
      )
      this.publicKey = keyPair.publicKey
      this.privateKey = keyPair.privateKey
      this.publicKeyBase64 = Base64Utils.bufferToBase64(await crypto.subtle.exportKey('spki', this.publicKey))
      this.privateKeyBase64 = Base64Utils.bufferToBase64(await crypto.subtle.exportKey('pkcs8', this.privateKey))
    } catch (error) {
      console.error('生成密钥对失败:', error)
      throw error
    }
  }

  /**
   * 导出公钥为 Base64 格式的字符串
   * @returns Base64 格式的公钥
   */
  exportPublicKey(): string {
    if (!this.publicKey) {
      throw new Error('公钥未设置')
    }
    return this.publicKeyBase64 as string
  }

  /**
   * 导出私钥为 Base64 格式的字符串
   * @returns Base64 格式的私钥
   */
  exportPrivateKey(): string {
    if (!this.privateKey) {
      throw new Error('私钥未设置')
    }
    return this.privateKeyBase64 as string
  }

  /**
   * 加密数据
   * @param data - 要加密的数据
   * @returns 加密后的 Hex 格式字符串
   */
  async encryptData(data: string): Promise<string> {
    await this.initialize()
    if (!this.publicKey) {
      throw new Error('公钥未设置')
    }

    try {
      const encoder = new TextEncoder()
      const dataBuffer = encoder.encode(data)
      const encryptedBuffer = await crypto.subtle.encrypt(
        {
          name: 'RSA-OAEP'
        },
        this.publicKey,
        dataBuffer
      )
      return HexUtils.bufferToHex(encryptedBuffer)
    } catch (error) {
      console.error('加密数据失败:', error)
      throw error
    }
  }

  /**
   * 解密数据
   * @param encryptedHex - 要解密的 Hex 格式字符串
   * @returns 解密后的字符串
   */
  async decryptData(encryptedHex: string): Promise<string> {
    await this.initialize()
    if (!this.privateKey) {
      throw new Error('私钥未设置')
    }

    try {
      const encryptedBuffer = HexUtils.hexToBuffer(encryptedHex)
      const decryptedBuffer = await crypto.subtle.decrypt(
        {
          name: 'RSA-OAEP'
        },
        this.privateKey,
        encryptedBuffer
      )
      const decoder = new TextDecoder()
      return decoder.decode(decryptedBuffer)
    } catch (error) {
      console.error('解密数据失败:', error)
      throw error
    }
  }

}
